Date.ISO8601_RE = /(\d{4})-?(\d{2})?-?(\d{2})?[T ]?(\d{2})?:?(\d{2})?:?(\d{2})?[.,]?(\d*)(Z|[-+]\d{2}:?\d{2})?/;
Date.parseISO8601 = function(str)
{
	// 2004-12-16T06:59:43,490-08:00
	// 2004-12-09T04:37:48Z
	// trailing Z => UTC format
	try {
		var m = this.ISO8601_RE.exec(str);
		// reset the regexp object
		this.ISO8601_RE.lastIndex = 0;
		var d = new Date();
		d.setUTCFullYear(m[1]);
		if (m[2]) d.setUTCMonth(parseInt(m[2])-1);
		if (m[3]) d.setUTCDate(m[3]);
		if (m[4]) d.setUTCHours(m[4]);
		if (m[5]) d.setUTCMinutes(m[5]);
		if (m[6]) d.setUTCSeconds(m[6]);
		if (m[7]) {
			var ms = m[7];
			if (ms.length < 3) ms = ("00"+ ms).slice(-3);
			else if (ms.length > 3) ms = ms.slice(0,3);
			d.setUTCMilliseconds(ms);
		}
		else d.setUTCMilliseconds(0);
		if (!m[8]) m[8] = "Z";
		if (m[8] != "Z") { // locale time, convert to UTC
			var lm = /([-+])(\d{2}):?(\d{2})/.exec(m[8]);
			var offsetSign = lm[1];
			var hours = parseInt(lm[2], 10);
			var minutes = parseInt(lm[3], 10);
			var milliseconds = ((hours * 60) + minutes) * 60 * 1000;
			var time = d.getTime();
			var new_time = 0;
			if (offsetSign == "+") {
				new_time = time - milliseconds;
			} else {
				new_time = time + milliseconds;
			}
			d.setTime(new_time);
		}
		return d;
	} catch(e) {
		throw "Error parsing ISO 8601 datestring: '"+ str +"'; "+ e;
	}
};

Date.prototype.toISO8601String = function(localTime)
{
	if (typeof localTime == "undefined") localTime = false;
	var result = "";
	if (localTime) {
		// 2004-12-16T06:59:43,490+01:00
		var offset = this.getTimezoneOffset();
		var offsetSign = "-";
		if (offset <= 0) {
			offsetSign = "+";
			offset = -offset;
		}
		var offsetHours = Math.floor(offset / 60);
		var offsetMinutes = offset - offsetHours * 60;
		result = this.getFullYear() +
			"-" + ("0" + (this.getMonth() + 1)).slice(-2) +
			"-" + ("0" + this.getDate()).slice(-2) +
			"T" + ("0" + this.getHours()).slice(-2) +
			":" + ("0" + this.getMinutes()).slice(-2) +
			":" + ("0" + this.getSeconds()).slice(-2) +
			((this.getMilliseconds() != 0)? "," + ("00" + this.getMilliseconds()).slice(-3) : "") +
			offsetSign + ("0" + offsetHours).slice(-2) +
			":" + ("0" + offsetMinutes).slice(-2);
	}
	else {
		// 2004-12-09T04:37:48,490Z
		result = this.getUTCFullYear() +
			"-"+ ("0"+ (this.getUTCMonth()+1)).slice(-2) +
			"-"+ ("0"+ this.getUTCDate()).slice(-2) +
			"T"+ ("0"+ this.getUTCHours()).slice(-2) +
			":"+ ("0"+ this.getUTCMinutes()).slice(-2) +
			":"+ ("0"+ this.getUTCSeconds()).slice(-2) +
			((this.getUTCMilliseconds() != 0)? ","+ ("00"+ this.getUTCMilliseconds()).slice(-3) : "") +
			"Z";
	}
	return result;
};

/**
 * @author jessehu
 *
 * return a description of "1 hour ago" from date1 to date2
 */
Date.getDateIntervalDesc = function(date1, date2) {
	year = date1.getFullYear() - date2.getFullYear();
	month = date1.getMonth() - date2.getMonth();
	day = date1.getDate() - date2.getDate();
	hour = date1.getHours() - date2.getHours();
	min = date1.getMinutes() - date2.getMinutes();
	sec = date1.getSeconds() - date2.getSeconds();
		
	var desc = "";
	if (year > 0) {
		if (month > 0)
			desc = year + " year(s) " + month + " month(s) ago"
		else if (month == 0)
			desc = year + " year(s) ago"
		else 
			desc = (year > 1 ? (year - 1) + " year(s) " : "") + (month + 12) + " month(s) ago"
	}	
	else if (month > 0)
		desc = month + " month(s) ago"
	else if (day > 0)
		desc = day + " day(s) ago"
	else if (hour > 0)
		desc = hour + " hour(s) ago"
	else if (min > 0)
		desc = min + " minute(s) ago"
	else if (sec > 0)
		desc = sec + " second(s) ago"
	else 
		desc = "just now"
		
	return desc;
};
